package service

import (
	"github.com/google/uuid"
	"strconv"
	"time"
	"vrcm/src/vrcm/app/admin/models/comment"
	"vrcm/src/vrcm/app/admin/models/live_schedule"
	"vrcm/src/vrcm/app/admin/models/media"
	baiduService "vrcm/src/vrcm/app/admin/service/baidu"
	dto "vrcm/src/vrcm/app/admin/service/dto/baidu"
	mediaDto "vrcm/src/vrcm/app/admin/service/dto/media"
	streamHubService "vrcm/src/vrcm/app/admin/service/stream_hub"
	cDto "vrcm/src/vrcm/common/dto"
	"vrcm/src/vrcm/common/service"
	ext "vrcm/src/vrcm/envconfig"
)

type Asset struct {
	service.Service
}

func (e *Asset) SaveAssetAudit(c *mediaDto.VideoAuditReq) error {

	now := time.Now().Unix()
	audit := live_schedule.AuditResult{}
	audit.TenantId = c.TenantId
	audit.AssetId = c.AssetId
	audit.AuditType = 2
	audit.FrameTimeStamp = c.FrameTimeStamp
	audit.Id = c.Id
	audit.CreateTime = now
	audit.UpdateTime = now
	err := e.Orm.Save(audit).Error
	if err != nil {
		e.Log.Errorf("Create AuditResult error:%s \r\n", err)
	}
	return nil
}

func (e *Asset) CreateAIAssetAudit(c *mediaDto.LongVideoAuditReq) error {
	tx := e.Orm.Begin()
	defer func() {
		if r := recover(); r != nil {
			e.Log.Errorf("CreateLive error:%s \r\n", r)
			tx.Rollback()
			//return
		}
	}()
	if err := tx.Error; err != nil {
		return err
	}
	now := time.Now().Unix()
	assetIds := make([]string, 0, 3)
	assetMap := make(map[string]string)
	for _, v := range c.Assets {
		v := v
		assetIds = append(assetIds, v.AssetId)
		assetMap[v.AssetId] = v.AssetUrl
	}

	//获取审核任务中不存在的素材id
	notAssets := make([]media.AssetAudit, 0, 5)
	originAssets := make([]media.AssetAudit, 0, 5)
	originAssetMap := make(map[string]media.AssetAudit)
	err := tx.Model(&media.AssetAudit{}).Where("asset_id in ? and tenant_id=?", assetIds, c.TenantId).Find(&originAssets).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("get AssetAudit error:%s \r\n", err)
		return err
	}
	for _, v := range originAssets {
		v := v
		originAssetMap[v.AssetId] = v
	}

	//获取数据库不存在的素材审核任务
	for _, v := range c.Assets {
		v := v
		_, ok := originAssetMap[v.AssetId]
		if !ok {
			notAssets = append(notAssets, v)
		}
	}

	//创建第一次审核记录
	assets := make([]media.AssetAudit, 0, 5)
	for _, v := range notAssets {
		v := v
		m := media.AssetAudit{}
		m.TenantId = c.TenantId
		m.AssetId = v.AssetId
		url := assetMap[v.AssetId]
		m.AssetUrl = url
		m.AIAuditState = 2
		m.AuditState = 3
		m.CreateTime = now
		m.UpdateTime = now
		assets = append(assets, m)
	}
	if len(assets) > 0 {
		err = tx.Model(&media.AssetAudit{}).Create(&assets).Error
		if err != nil {
			tx.Rollback()
			e.Log.Errorf("get AssetAudit error:%s \r\n", err)
			return err
		}
	}

	assetAudits := make([]media.AssetAudit, 0, 5)
	err = tx.Model(&media.AssetAudit{}).Where("asset_id in ?", assetIds).Find(&assetAudits).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("get AssetAudit error:%s \r\n", err)
		return err
	}
	auditMap := make(map[string]struct{})
	for _, v := range assetAudits {
		//已审核就跳过
		if v.AIAuditState == 1 {
			auditMap[v.AssetId] = struct{}{}
		}
	}

	baiduService := &baiduService.BaiduService{}
	baiduService.Log = e.Log
	for k, v := range assetAudits {
		v := v
		_, ok := auditMap[v.AssetId]
		if ok {
			continue
		}
		//创建素材审核
		streamReq := &dto.LongVideoAuditReq{}
		streamReq.StrategyId = int64(ext.ExtConfig.ServiceConfig.StrategyId)
		streamReq.TenantId = c.TenantId
		streamReq.AppId = c.AppId
		streamReq.Url = v.AssetUrl
		streamReq.Frequency = 5
		u := uuid.New()
		streamReq.ExtId = u.String()
		streamReq.SubEvents = "2,3"
		streamReq.NoticeUrl = "http://vpn.videosolar.com:18000" + "/api/v1/media/audit-callback"
		//streamReq.NoticeUrl = ext.ExtConfig.ServiceConfig.VrcmServiceUrl + "/api/v1/media/audit-callback"
		streamReq.DetectType = 1
		//e.Log.Trace("AAAAAAAA")
		taskId, err := baiduService.LongVideoAuditSubmit(streamReq)
		if err != nil {
			tx.Rollback()
			e.Log.Errorf("CreateLive LongVideoAuditSubmit:%s \r\n", err)
			return err
		}
		*(&assetAudits[k].AuditTaskId) = taskId
		*(&assetAudits[k].AssetUrl) = v.AssetUrl
		*(&assetAudits[k].UpdateTime) = now
		*(&assetAudits[k].AIAuditState) = 1
	}
	if len(assetAudits) > 0 {
		err = tx.Save(assetAudits).Error
		if err != nil {
			tx.Rollback()
			e.Log.Errorf("save AssetAudit error:%s \r\n", err)
			return err
		}
	}
	tx.Commit()
	return nil
}

func (e *Asset) LongVideoAuditResultCallBack(c *dto.LongVideoData) error {
	tx := e.Orm.Begin()
	defer func() {
		if r := recover(); r != nil {
			e.Log.Errorf("Service LongVideoAuditResultCallBack error:%s \r\n", r)
			tx.Rollback()
			//return
		}
	}()
	if err := tx.Error; err != nil {
		return err
	}

	if len(c.Result.Frames) <= 0 {
		tx.Commit()
		return nil
	}
	e.Log.Trace("审核结果信息为：", *c)
	streamHubService := &streamHubService.StreamHubService{}
	streamHubService.Log = e.Log
	//审核任务
	auditTask := media.AssetAudit{}
	err := tx.Model(&media.AssetAudit{}).Where("audit_task_id=?", c.TaskId).Find(&auditTask).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("get AssetAudit error:%s \r\n", err)
		return err
	}
	if auditTask.Id <= 0 {
		tx.Commit()
		return err
	}
	now := time.Now().Unix()
	results := make([]live_schedule.AuditResult, 0, 5)

	for _, v := range c.Result.Frames {
		v := v
		flagMap := map[int]struct{}{}
		for _, d := range v.Data {
			violationType := 0
			switch d.Type {
			case 1:
				violationType = 1
			case 2:
				violationType = 2
			case 3:
				violationType = 3
			case 4:
				violationType = 4
			case 5:
				violationType = 5
			default:
				violationType = 6

			}
			flagMap[violationType] = struct{}{}
			result := live_schedule.AuditResult{}
			result.TenantId = auditTask.TenantId
			auditId := strconv.FormatInt(c.TaskId, 10)
			result.AuditTaskId = auditId
			result.ViolationType = violationType
			result.FrameTimeStamp = v.FrameTimeStamp
			result.SubType = d.SubType
			result.AssetId = auditTask.AssetId
			result.ImgUrl = v.FrameUrl
			result.AuditType = 2
			result.CreateTime = now
			result.UpdateTime = now
			results = append(results, result)
		}

	}
	if len(results) > 0 {
		err = tx.Model(&live_schedule.AuditResult{}).Create(&results).Error
		if err != nil {
			tx.Rollback()
			e.Log.Errorf("create AuditResult error:%s \r\n", err)
			return err
		}
	}

	tx.Commit()
	return nil
}

func (e *Asset) GetAuditStatisticByAsset(c *dto.GetAuditResultByAssetReq) (*mediaDto.AuditStatisticRes, error) {
	results := make([]mediaDto.AuditStatisticDetailRes, 0, 5)
	db := e.Orm.Model(&live_schedule.AuditResult{})
	db.Where("audit_type =2 and asset_id=? and tenant_id=?", c.AssetId, c.TenantId)
	err := db.Select("violation_type,task_id, count(*) as type_num").
		Group("violation_type,task_id").Scan(&results).Error
	if err != nil {
		e.Log.Errorf("create AuditResult error:%s \r\n", err)
		return nil, err
	}

	res := mediaDto.AuditStatisticRes{}
	res.AssetId = c.AssetId
	t1 := 0
	t2 := 0
	t3 := 0
	t4 := 0
	t5 := 0
	t6 := 0
	for _, d := range results {
		switch d.ViolationType {
		case 1:
			t1 += d.TypeNum
		case 2:
			t2 += d.TypeNum
		case 3:
			t3 += d.TypeNum
		case 4:
			t4 += d.TypeNum
		case 5:
			t5 += d.TypeNum
		default:
			t6 += d.TypeNum
		}
	}
	res.Type1Num = t1
	res.Type2Num = t2
	res.Type3Num = t3
	res.Type4Num = t4
	res.Type5Num = t5
	res.Type6Num = t6
	return &res, nil
}

func (e *Asset) GetAuditStatisticByType(c *dto.GetAuditResultDetailByTypeReq, count *int64) (*[]live_schedule.AuditResult, error) {
	results := make([]live_schedule.AuditResult, 0, 5)
	db := e.Orm.Model(&live_schedule.AuditResult{}).
		Scopes(
			cDto.Paginate(c.PageSize, c.PageIndex),
		).Where("asset_id=? and audit_type =2 and tenant_id=?", c.AssetId, c.TenantId)
	if len(c.ViolationType) > 0 {
		db.Where("violation_type in ?", c.ViolationType)
	}
	err := db.Find(&results).Limit(-1).Offset(-1).
		Count(count).Error
	if err != nil {
		e.Log.Errorf("GetAuditStatisticByType GetPage error:%s \r\n", err)
		return nil, err
	}
	return &results, nil
}

func (e *Asset) UpdateAuditState(c *mediaDto.UpdateAuditState) error {
	tx := e.Orm.Begin()
	defer func() {
		if r := recover(); r != nil {
			e.Log.Errorf("UpdateAuditState error:%s \r\n", r)
			tx.Rollback()
		}
	}()
	if err := tx.Error; err != nil {
		tx.Rollback()
		e.Log.Errorf("UpdateAuditState error:%s \r\n", err)
		return err
	}
	now := time.Now().Unix()
	assetAudit := media.AssetAudit{}
	err := tx.Model(&media.AssetAudit{}).Where("asset_id=? and tenant_id=?", c.AssetId, c.TenantId).Find(&assetAudit).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("get AssetAudit error:%s \r\n", err)
		return err
	}

	//没有素材审核需要创建素材审核
	if assetAudit.Id <= 0 {
		audit := media.AssetAudit{}
		audit.TenantId = c.TenantId
		audit.AssetId = c.AssetId
		audit.Account = c.Account
		audit.AuditState = c.AuditState
		audit.AIAuditState = 2
		audit.CreateTime = now
		audit.UpdateTime = now
		err = tx.Model(&media.AssetAudit{}).Create(&assetAudit).Error
		if err != nil {
			e.Log.Errorf("Create AssetAudit error:%s \r\n", err)
		}
	}

	err = tx.Model(&media.AssetAudit{}).
		Where("asset_id=?", c.AssetId).
		Update("audit_state", c.AuditState).
		Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("UpdateAuditState error:%s \r\n", err)
		return err
	}

	history := live_schedule.AuditHistory{}
	history.AssetID = c.AssetId
	history.AuditState = c.AuditState
	history.TenantID = c.TenantId
	history.Account = c.Account
	history.AuditTimeStamp = now
	history.CreateTime = now
	history.UpdateTime = now
	err = tx.Model(&live_schedule.AuditHistory{}).Create(&history).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("create AuditHistory error:%s \r\n", err)
		return err
	}
	tx.Commit()
	return nil
}

func (e *Asset) GetAuditHistoryByAsset(c *mediaDto.GetAuditState) (*[]live_schedule.AuditHistory, error) {

	histories := make([]live_schedule.AuditHistory, 0, 5)
	err := e.Orm.Model(&live_schedule.AuditHistory{}).
		Where("asset_id=? and tenant_id =?", c.AssetId, c.TenantId).
		Order("create_time desc").
		Find(&histories).
		Error
	if err != nil {
		e.Log.Errorf("get AuditHistory error:%s \r\n", err)
		return nil, err
	}
	return &histories, nil
}

func (e *Asset) GetAudit(c *mediaDto.GetAudit) (*media.AssetAudit, error) {

	var audit media.AssetAudit
	err := e.Orm.Model(&media.AssetAudit{}).Where("asset_id=? and tenant_id=?", c.AssetId, c.TenantId).Find(&audit).Error
	if err != nil {
		e.Log.Errorf("get AssetAudit error:%s ", err)
		return nil, err
	}
	return &audit, nil
}

func (e *Asset) DeleteAssetAudit(c *mediaDto.DeleteAssetAudit) error {

	tx := e.Orm.Begin()
	defer func() {
		if r := recover(); r != nil {
			e.Log.Errorf("DeleteAssetAudit error:%s \r\n", r)
			tx.Rollback()
		}
	}()
	if err := tx.Error; err != nil {
		tx.Rollback()
		e.Log.Errorf("DeleteAssetAudit error:%s \r\n", err)
		return err
	}
	if len(c.AssetIds) <= 0 {
		return nil
	}

	err := tx.Model(&media.AssetAudit{}).Where("asset_id in ? and tenant_id=?", c.AssetIds, c.TenantId).Delete(&media.AssetAudit{}).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("delete AssetAudit error:%s ", err)
		return err
	}

	err = tx.Model(&live_schedule.AuditResult{}).Where("asset_id in ? and tenant_id=?", c.AssetIds, c.TenantId).Delete(&live_schedule.AuditResult{}).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("delete AuditResult error:%s ", err)
		return err
	}
	err = tx.Model(&comment.Comment{}).Where("bind_id in ? and tenant_id=?", c.AssetIds, c.TenantId).Delete(&comment.Comment{}).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("delete Comment error:%s ", err)
		return err
	}

	err = e.Orm.Model(&live_schedule.AuditHistory{}).Where("asset_id in ? and tenant_id=?", c.AssetIds, c.TenantId).Delete(&live_schedule.AuditHistory{}).Error
	if err != nil {
		tx.Rollback()
		e.Log.Errorf("delete AuditHistory error:%s ", err)
		return err
	}
	tx.Commit()
	return nil
}

func (e *Asset) GetMediaAssetAuditStatic(c *mediaDto.GetAuditStatic) ([]live_schedule.AuditResult, error) {

	results := make([]live_schedule.AuditResult, 0, 5)
	err := e.Orm.Model(&live_schedule.AuditResult{}).Where("tenant_id=? and audit_type = 2 and  create_time >? and  create_time<?", c.TenantId, c.StartTime, c.EndTime).Find(&results).Error
	if err != nil {
		e.Log.Errorf("get AuditResult error:%s ", err)
		return results, err
	}
	return results, nil
}
